package cn.lavenir.fyai.rag.stream;

import dev.langchain4j.service.MemoryId;
import dev.langchain4j.service.SystemMessage;
import dev.langchain4j.service.UserMessage;
import dev.langchain4j.service.spring.AiService;
import dev.langchain4j.service.spring.AiServiceWiringMode;
import reactor.core.publisher.Flux;

/**
 * AiServices会组装Assistant接口以及其他组件，并使用反射机制创建一个实现Assistant接口的代理对象。
 * 这个代理对象会处理输入和输出的所有转换工作。在这个例子中，chat方法的输入是一个字符串，但是大
 * 模型需要一个 UserMessage 对象。所以，代理对象将这个字符串转换为 UserMessage ，并调用聊天语
 * 言模型。chat方法的输出类型也是字符串，但是大模型返回的是 AiMessage 对象，代理对象会将其转换
 * 为字符串。
 * 简单理解就是：代理对象的作用是输入转换和输出转换
 */
@AiService(
        wiringMode = AiServiceWiringMode.EXPLICIT,
        streamingChatModel = "qwenStreamingChatModel",
        chatMemory = "chatMemory",
        chatMemoryProvider = "chatMemoryProvider",
        tools = "calculatorTools",
        contentRetriever = "contentRetriever")
public interface Assistant {

    /**
     * @SystemMessage 的内容将在后台转换为 SystemMessage 对象，并与 UserMessage 一起发送给大语
     * 言模型（LLM）。
     * SystemMessaged的内容只会发送给大模型一次。
     * 如果你修改了SystemMessage的内容，新的SystemMessage会被发送给大模型，之前的聊天记忆会失效。
     * 如果要显示今天的日期，我们需要在提示词中添加当前日期的占位符{{current_date}}
     *  @UserMessage：获取用户输入
     *
     *  @V 明确指定传递的参数名称
     */
    @SystemMessage("你是一个代码规范方面的专家。今天是{{current_date}}")
    //从资源中加载提示模板
//    @SystemMessage(fromResource = "my-prompt-template.txt")
    //@UserMessage("你是我的好朋友，并且添加一些表情符号。 {{it}}") //{{it}}表示这里
    //@UserMessage("你是我的好朋友，请用上海话回答问题，并且添加一些表情符号。{{message}}")
    Flux<String> chat(@MemoryId int memoryId, @UserMessage String userMessage);
}


